package io.bdmc.core.snmp;

import io.bdmc.common.exception.FileLengthNotEnoughException;
import io.bdmc.common.utils.Constant;
import io.bdmc.modules.bss.model.SorEvent;
import io.bdmc.modules.bss.model.SorFileParser;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

public class SORFileParserTool {
    public static byte[] readToString(String filePath) {
        File file = new File(filePath);
        // File file = new File(filePath);
        long fileSize = file.length();
        byte[] fileContent = new byte[(int) fileSize];
        try {
            FileInputStream in = new FileInputStream(file);
            in.read(fileContent);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileContent;
    }

    public static SorFileParser parserSorFile(String filePath) throws FileLengthNotEnoughException {
        System.out.println("path:" + filePath);
        byte[] dataBs = readToString(Constant.EXPORTPATH + filePath);
        return parserSorFileBs(dataBs);
    }

    public static SorFileParser parserSorFileBs(byte[] dataBs) throws FileLengthNotEnoughException {

        String sorStartHexStr = GwUtil.bytesToHexString(subBytes(dataBs, 0, 4));
        SorFileParser sor = new SorFileParser();
        if (sorStartHexStr.equals("4D617000")) {

            long dateTimeStamp = GwUtil.DWord2long(subBytes(dataBs, 0xD8, 4));
            sor.setDateTimeStamp(dateTimeStamp);

            // 实际波长单位nm
            int actualWavelength = GwUtil.Word2Int(subBytes(dataBs, 0xDE, 2)) / 10;
            sor.setActualWavelength(actualWavelength);
            // 脉冲宽度单位ns
            int pulseWidthsUsed = GwUtil.Word2Int(subBytes(dataBs, 0xEA, 2));
            sor.setPulseWidthsUsed(pulseWidthsUsed);
            // 数据间距
            long dataSpacing = GwUtil.DWord2long(subBytes(dataBs, 0xEC, 4));
            double ds = dataSpacing / 500000.0 * 1.023;
            BigDecimal b = new BigDecimal(ds);
            ds = b.setScale(5, RoundingMode.HALF_DOWN).doubleValue();
            sor.setDataSpacing(ds);

            // 每个脉冲宽度的数据点数量
            long numberDataPoint = GwUtil.DWord2long(subBytes(dataBs, 0xF0, 4));
            sor.setNumberDataPoint(numberDataPoint);
            // 折射率
            double groupIndex = GwUtil.DWord2long(subBytes(dataBs, 0xF4, 4)) / 100000.0;
            sor.setGroupIndex(groupIndex);
            // 平均化次数
            int averagesNum = GwUtil.DWord2Int(subBytes(dataBs, 0xFA, 4));
            sor.setAveragesNum(averagesNum);
            // 量程 单位m
            int acquisitionRangeDistance = GwUtil.DWord2Int(subBytes(dataBs, 0x0104, 4)) / 10;
            sor.setAcquisitionRangeDistance(acquisitionRangeDistance);
            // 事件总数
            int eventAllNum = GwUtil.Word2Int(subBytes(dataBs, 0x134, 2));
            sor.setEventAllNum(eventAllNum);

            byte[] eventBs = subBytes(dataBs, 0x136, 43 * eventAllNum);
            sor.setSorEvents(parserEvent(eventBs, eventAllNum));
            int beginIndex = 0x136 + 43 * eventAllNum;
            // 端点间总损耗
            double end2EndLoss = GwUtil.DWord2Int(subBytes(dataBs, beginIndex, 4)) / 1000.0;
            sor.setEnd2EndLoss(end2EndLoss);
            // 回波损耗
            int opticalReturnLoss = GwUtil.Word2Int(subBytes(dataBs, beginIndex + 12, 2));
            double rl = opticalReturnLoss / 1000.0;
            String rlresult = String.format("%.3f", rl);
            sor.setOpticalReturnLoss(rlresult);
            // 数据点数量
            int numberDataPoints = GwUtil.Word2Int(subBytes(dataBs, beginIndex + 75, 4));
            sor.setNumberDataPoints(numberDataPoints);
            try {
                int eventDataLen = beginIndex + 75 + 12 + numberDataPoints * 2;
                byte[] dataPointsBs;
                if (dataBs.length < eventDataLen) {
                    dataPointsBs = subBytes(dataBs, beginIndex + 75 + 12, dataBs.length - beginIndex - 75 - 12);
                } else {
                    dataPointsBs = subBytes(dataBs, beginIndex + 75 + 12, numberDataPoints * 2);
                }

                List<Double> dataPointsLt = parsePoint(dataPointsBs);
                sor.setDataPointsLt(dataPointsLt);
                return sor;
            } catch (Exception e) {
                throw new FileLengthNotEnoughException("文件长度不足，无法解析！");
            }
        }
        return null;
    }

    public static List<Double> parsePoint(byte[] dataBs) {
        List<Double> lt = new ArrayList<Double>();
        for (int i = 0; i < dataBs.length / 2; i++) {
            double pointSF = GwUtil.Word2Int(subBytes(dataBs, 2 * i, 2)) / 1000.0 * -1;
            lt.add(pointSF);
        }
        return lt;
    }

    public static List<SorEvent> parserEvent(byte[] dataBs, int count) {

        List<SorEvent> sorEvents = new ArrayList<SorEvent>();
        List<SorEvent> refEvents = new ArrayList<SorEvent>();// 反射点
        // SorEvent endPoint = null;//终端
        for (int i = 0; i < count; i++) {
            SorEvent sorEvent = new SorEvent();
            int eventNumber = GwUtil.Word2Int(subBytes(dataBs, 43 * i + 0, 2));
            sorEvent.setEventNumber(eventNumber);
            // 事件传播时间
            int eventPropagationTime = GwUtil.DWord2Int(subBytes(dataBs, 43 * i + 2, 4));
            sorEvent.setEventPropagationTime(eventPropagationTime);
            double dis = 25333.9 / 1238000000.0 * eventPropagationTime;

            sorEvent.setEventPropagationDistance(String.format("%.3f", dis));

            // 光纤衰减系数
            double attenuationCoefficientLeadInFiber = GwUtil.Word2Int(subBytes(dataBs, 43 * i + 6, 2)) / 1000.0;
            sorEvent.setAttenuationCoefficientLeadInFiber(attenuationCoefficientLeadInFiber);
            // 事件损失
            int eventLoss = GwUtil.Word2Int(subBytes(dataBs, 43 * i + 8, 2));
            if (eventLoss > 32768) {
                eventLoss = eventLoss - 65536;
            }
            double loss = eventLoss / 1000.0;
            String lossStr = String.format("%.3f", loss);
            sorEvent.setEventLoss(lossStr);

            double eventReflectance = GwUtil.DWord2Int(subBytes(dataBs, 43 * i + 10, 4)) / 1000.0;
            sorEvent.setReflcetivity(String.format("%.3f", eventReflectance));
            // 事件代码
            String eventCode = GwUtil.byteArrayToStr(subBytes(dataBs, 43 * i + 14, 6));
            sorEvent.setEventCode(eventCode);
            // 总损耗
            if (eventCode.startsWith("1F") || eventCode.startsWith("0F") || eventCode.startsWith("R")
                    || eventCode.startsWith("N") || eventCode.startsWith("E")) {// 反射点计算总损耗
                double totalLosses = dis * attenuationCoefficientLeadInFiber + Math.abs(loss);
                String totalLossesStr = String.format("%.3f", totalLosses);
                sorEvent.setTotalLosses(totalLossesStr);
                refEvents.add(sorEvent);
            } else if (eventCode.contains("0E")) {
                // 光缆终端
                // endPoint = sorEvent;
            }

            sorEvents.add(sorEvent);
        }
        return sorEvents;

    }

    public static byte[] subBytes(byte[] src, int begin, int count) {
        byte[] bs = new byte[count];
        System.arraycopy(src, begin, bs, 0, count);
        return bs;
    }

}